import React from 'react';
import ReactDOM from 'react-dom';
import marked from 'marked';
import { transform } from '@babel/standalone';
import Editor from './editor';
import iconTemp from './icon-search-engine';

window.React = React;
window.ReactDOM = ReactDOM;
// registerPlugin('transform-typescript', TransformTypescriptPlugin);

export default class CodeEngine extends React.Component {
  constructor(props) {
    super(props);

    this.playerId = `${parseInt(Math.random() * 1e9).toString(36)}`;
    this.document = this.props.children.match(/([^]*)\n?(```[^]+```)/);
    this.description = marked(this.document[1]);
    this.source = this.document[2].match(/```(.*)\n?([^]+)```/);

    this.state = {
      showBlock: false
    };
  }

  componentDidMount() {
    this.renderSource(this.source[1], this.source[2]);
  }

  componentWillUnmount() {
    this.unmountPlayer();
  }

  unmountPlayer() {
    const player = document.getElementById(this.playerId);
    if (player) {
      ReactDOM.unmountComponentAtNode(document.getElementById(this.playerId))
    }
  }

  blockControl() {
    this.setState({
      showBlock: !this.state.showBlock
    });
  }

  renderSource(lan, value) {
    this.unmountPlayer();
    import('../../src/index.ts').then(bricks => {
      window.bricks = bricks;
      const args = ['context', 'React', 'ReactDOM'];
      const argv = [this, React, ReactDOM];

      for (const key in bricks) {
        args.push(key);
        argv.push(bricks[key]);
      }

      args.push('PLAYER_ID');
      argv.push(this.playerId);

      return {
        args,
        argv
      };
    }).then(({ args, argv }) => {
      let lan = this.source[1];
      let finalValue = value;
      if (lan === 'html') {
        let scripts = /<script>([\S\s]+)<\/script>/gi.exec(value);
        console.log(scripts);
        let script = '';
        if (scripts) {
          script = scripts[1];
          finalValue = value.replace(scripts[0],"");
        }
        finalValue = `
        componentDidMount() {
          window.eval(\`${script}\`);
          console.log(\`${script}\`);
        }
        componentDidUpdate() {
          window.eval(\`${script}\`);
        }
        render() {
          return <div dangerouslySetInnerHTML={{ __html: \`${finalValue}\` }} />
        }
        `
      }

      // 处理 icon search
      if (lan === 'js-icon') {
        finalValue = iconTemp(finalValue);
      }

      finalValue = finalValue.trim();

      if (!/class\s+(\w+)\s+extends/.test(finalValue)) {
        finalValue = `
          class Demo extends React.Component {
            ${finalValue}
          }
        `
      }

      if (lan === 'tsx') {
        finalValue = value + ';ReactDOM.render(<Demo {...context.props}/>, document.getElementById(PLAYER_ID))';
      } else {
        finalValue += ';ReactDOM.render(<Demo {...context.props}/>, document.getElementById(PLAYER_ID))'
      }

      const code = transform(`
        ${finalValue}
      `, {
        presets: ['es2015', 'react'],
        plugins: [['transform-typescript', { isTSX: true }]]
      }).code;

      args.push(code);

      console.log(args);
      new Function(...args).apply(null, argv);

      this.source[2] = value
    }).catch((err) => {
      console.log('error----------', err);
      if (process.env.NODE_ENV !== 'production') {
        throw err;
      }
    })
  }

  render() {
    return (
      <div className="main-panel">
        <div className="main-panel-source" id={this.playerId} />
        {
          this.description && (
            <div
              ref="description"
              className="main-panel-description"
              dangerouslySetInnerHTML={{ __html: this.description }}
            />
          )
        }
        {
          this.state.showBlock && (
            <div>
              <Editor
                value={this.source[2]}
                onChange={code => this.renderSource(this.source[2], code)}
              />
            </div>
          )
        }
         <div className="main-panel-control" onClick={this.blockControl.bind(this)}>
          {
            this.state.showBlock ? (
              <span>隐藏代码</span>
            ) : (
              <span>显示代码</span>
            )
          }
        </div>
      </div>
    )
  }
}
